home *** CD-ROM | disk | FTP | other *** search
/ Turnbull China Bikeride / Turnbull China Bikeride - Disc 1.iso / DEMON / RISCOS2 / TCP_131S.ARC / c / nr3 < prev    next >
Text File  |  1993-12-22  |  34KB  |  927 lines

  1. /* net/rom level 3 low level processing
  2.  * Copyright 1989 by Daniel M. Frank, W9NK.  Permission granted for
  3.  * non-commercial distribution only.
  4.  */
  5.  
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <time.h>
  10. #include <ctype.h>
  11. #include "global.h"
  12. #include "mbuf.h"
  13. #include "iface.h"
  14. #include "timer.h"
  15. #include "arp.h"
  16. #include "slip.h"
  17. #include "ax25.h"
  18. #include "netrom.h"
  19. #include "nr4.h"
  20. #include "lapb.h"
  21. #include "ip.h"
  22. #include "misc.h"
  23.  
  24. static int ismycall(struct ax25_addr *);
  25. static int accept_bc(struct ax25_addr *, unsigned);
  26. static struct nr_bind *find_worst(struct nr_bind *);
  27. static struct nr_bind *find_best(struct nr_bind *, unsigned int);
  28.  
  29. /* Nodes message broadcast address: "NODES" in shifted ASCII */
  30. struct ax25_addr nr_nodebc = {
  31.         'N'<<1, 'O'<<1, 'D'<<1, 'E'<<1, 'S'<<1, ' '<<1,
  32.         ('0'<<1) | E
  33. } ;
  34.  
  35. struct nriface nrifaces[NRNUMIFACE] ;
  36. unsigned nr_numiface ;
  37. struct nrnbr_tab *nrnbr_tab[NRNUMCHAINS] ;
  38. struct nrroute_tab *nrroute_tab[NRNUMCHAINS] ;
  39. struct nrnf_tab *nrnf_tab[NRNUMCHAINS] ;
  40. unsigned nr_nfmode = NRNF_NOFILTER ;
  41. unsigned char nr_ttl = 15 ;
  42. unsigned obso_init = 6 ;
  43. unsigned obso_minbc = 5 ;
  44. unsigned nr_maxroutes = 5 ;
  45. unsigned nr_autofloor = 10 ;
  46. unsigned nr_verbose = 1 ;
  47. struct interface *nr_interface ;
  48.  
  49. /* send a NET/ROM layer 3 datagram */
  50. void nr3output(struct ax25_addr *dest, struct mbuf *data)
  51. {
  52.         struct nr3hdr n3hdr ;
  53.         struct mbuf *n3b ;
  54.  
  55.         n3hdr.dest = *dest ;    /* copy destination field */
  56.         n3hdr.ttl = nr_ttl ;    /* time to live from initializer parm */
  57.  
  58.         if ((n3b = htonnr3(&n3hdr)) == NULLBUF) {
  59.                 free_p(data) ;
  60.                 return ;
  61.         }
  62.  
  63.         append(&n3b, data) ;
  64.  
  65.         /* The null interface indicates that the packet needs to have */
  66.         /* an appropriate source address inserted by nr_route */
  67.         
  68.         nr_route(n3b,NULLAX25) ;
  69. }
  70.  
  71.  
  72. /* send IP datagrams across a net/rom network connection */
  73. int nr_send(struct mbuf *bp, struct interface *interface, int32 gateway,
  74.              char precedence, char delay, char throughput, char reliability)
  75. {
  76.         struct ax25_addr dest ;
  77.         struct mbuf *pbp ;
  78.         struct nr4hdr n4hdr ;
  79.         char *hwaddr ;
  80.         struct arp_tab *arp ;
  81.  
  82.         interface   = interface;
  83.         precedence  = precedence;
  84.         delay       = delay;
  85.         throughput  = throughput;
  86.         reliability = reliability;
  87.  
  88.         if ((arp = arp_lookup(ARP_NETROM,gateway)) == NULLARP) {
  89.                 free_p(bp) ;    /* drop the packet if no route */
  90.                 return -1;
  91.         }
  92.         hwaddr = arp->hw_addr ;                         /* points to destination */
  93.         memcpy(dest.call, hwaddr, ALEN) ;
  94.         dest.ssid = hwaddr[ALEN] ;
  95.                 
  96.         /* Create a "network extension" transport header */
  97.         n4hdr.opcode = NR4OPPID ;
  98.         n4hdr.u.pid.family = NRPROTO_IP ;
  99.         n4hdr.u.pid.proto = NRPROTO_IP ;
  100.  
  101.         if ((pbp = htonnr4(&n4hdr)) == NULLBUF) {
  102.                 free_p(bp) ;
  103.                 return -1;
  104.         }
  105.  
  106.         append(&pbp,bp) ;               /* Append the data to that */
  107.         nr3output(&dest, pbp) ; /* and pass off to level 3 code */
  108.         return 0;
  109. }
  110.  
  111. /* Figure out if a call is assigned to one of my net/rom
  112.  * interfaces.
  113.  */
  114. static int ismycall(struct ax25_addr *addr)
  115. {
  116.         register int i ;
  117.         int found = 0 ;
  118.         
  119.         for (i = 0 ; i < nr_numiface ; i++)
  120.                 if (addreq((struct ax25_addr *)(nrifaces[i].interface->hwaddr),
  121.                         addr)) {
  122.                         found = 1 ;
  123.                         break ;
  124.                 }
  125.  
  126.         return found ;
  127. }
  128.  
  129.  
  130. /* Route net/rom network layer packets.
  131.  */
  132. void nr_route(struct mbuf *bp, struct ax25_cb *iaxp)
  133. {
  134.         struct nr3hdr n3hdr ;
  135.         struct nr4hdr n4hdr ;
  136.         struct ax25_cb *axp;
  137.         struct ax25 naxhdr ;
  138.         struct ax25_addr neighbor, from ;
  139.         struct mbuf *hbp, *pbp ;
  140.         extern int16 axwindow ;
  141.         register struct nrnbr_tab *np ;
  142.         register struct nrroute_tab *rp ;
  143.         register struct nr_bind *bindp;
  144.         struct interface *interface ;
  145.         unsigned ifnum ;
  146.         
  147.         if (ntohnr3(&n3hdr,&bp) == -1) {
  148.                 free_p(bp) ;
  149.                 return ;
  150.         }
  151.  
  152.         /* If this isn't an internally generated network packet,
  153.          * give the router a chance to record a route back to the
  154.          * sender, in case they aren't in the local node's routing
  155.          * table yet.
  156.          */
  157.  
  158.         if (iaxp != NULLAX25) {
  159.                 /* find the interface number */
  160.                 for (ifnum = 0 ; ifnum < nr_numiface ; ifnum++)
  161.                         if (iaxp->interface == nrifaces[ifnum].interface)
  162.                                 break ;
  163.  
  164.                 if (ifnum == nr_numiface) {     /* shouldn't happen! */
  165.                         free_p(bp) ;
  166.                         return ;
  167.                 }
  168.  
  169.                 from = iaxp->addr.dest ;
  170.                 from.ssid |= E ;
  171.  
  172.                 /* Add (possibly) a zero-quality recorded route via */
  173.                 /* the neighbor from which this packet was received */
  174.                 /* Note that this doesn't work with digipeated neighbors, */
  175.                 /* at this point. Use ##temp as the alias. */
  176.                 
  177.                 (void) nr_routeadd("##temp",&n3hdr.source,ifnum,0,(char *)&from,0,1) ;
  178.                 
  179.         }
  180.  
  181.         /* A packet from me, to me, can only be one thing: */
  182.         /* a horrible routing loop.  This will probably result */
  183.         /* from a bad manual ARP entry, but we should fix these */
  184.         /* obscure errors as we find them. */
  185.         
  186.         if (ismycall(&n3hdr.dest)) {
  187.                 if (iaxp == NULLAX25) {         /* From me? */
  188.                         free_p(bp) ;
  189.                         return ;
  190.                 } else {                                        /* It's from somewhere else! */
  191.                         if (ntohnr4(&n4hdr,&bp) == -1) {
  192.                                 free_p(bp) ;
  193.                                 return ;
  194.                         }
  195.                         if ((n4hdr.opcode & NR4OPCODE) == 0) {
  196.                                 if (n4hdr.u.pid.family == NRPROTO_IP
  197.                                         && n4hdr.u.pid.proto == NRPROTO_IP)
  198.                                         ip_route(bp,0) ;
  199.                                 else                                    /* we don't do this proto */
  200.                                         free_p(bp) ;
  201.  
  202.                                 return ;
  203.                         }
  204.                         
  205.                         /* Must be net/rom transport: */
  206.  
  207.                         nr4input(&n4hdr,bp) ;
  208.  
  209.                 }
  210.                 return ;
  211.         }
  212.  
  213.         if ((rp = find_nrroute(&n3hdr.dest)) == NULLNRRTAB) {
  214.                 /* no route, drop the packet */
  215.                 free_p(bp) ;
  216.                 return ;
  217.         }
  218.  
  219.         if ((bindp = find_best(rp->routes,1)) == NULLNRBIND) {
  220.                 /* This shouldn't happen yet, but might if we add */
  221.                 /* dead route detection */
  222.                 free_p(bp) ;
  223.                 return ;
  224.         }
  225.  
  226.         np = bindp->via ;
  227.         memcpy(neighbor.call,np->call,ALEN) ;
  228.         neighbor.ssid = np->call[ALEN] ;
  229.         interface = nrifaces[np->interface].interface ;
  230.  
  231.         /* Now check to see if iaxp is null.  That is */
  232.         /* a signal that the packet originates here, */
  233.         /* so we need to insert the callsign of the appropriate  */
  234.         /* interface */
  235.         if (iaxp == NULLAX25)
  236.                 memcpy(&n3hdr.source,interface->hwaddr,AXALEN) ;
  237.         
  238.         /* Make sure there is a connection to the neighbor */
  239.         if ((axp = find_ax25(&neighbor)) == NULLAX25 ||
  240.                 (axp->state != CONNECTED && axp->state != RECOVERY)) {
  241.                 /* Open a new connection or reinitialize old one */
  242.                 /* hwaddr has been advanced to point to neighbor + digis */
  243.                 atohax25(&naxhdr, np->call, (struct ax25_addr *)interface->hwaddr) ;
  244.                 axp = open_ax25(&naxhdr, axwindow, (void (*)())ax_incom, NULLVFP, NULLVFP,
  245.                                                 interface,(char *)0) ;
  246.                 if (axp == NULLAX25) {
  247.                         free_p(bp) ;
  248.                         return ;
  249.                 }
  250.         }
  251.                 
  252.         if (--n3hdr.ttl == 0) { /* the packet's time to live is over! */
  253.                 free_p(bp) ;
  254.                 return ;
  255.         }
  256.  
  257.         /* allocate and fill PID mbuf */
  258.         if ((pbp = alloc_mbuf(1)) == NULLBUF) {
  259.                 free_p(bp) ;
  260.                 return ;
  261.         }
  262.         pbp->cnt = 1 ;
  263.         *pbp->data = PID_NETROM ;
  264.  
  265.         /* now format network header */
  266.         if ((hbp = htonnr3(&n3hdr)) == NULLBUF) {
  267.                 free_p(pbp) ;
  268.                 free_p(bp) ;
  269.                 return ;
  270.         }
  271.  
  272.         append(&pbp,hbp) ;              /* append header to pid */
  273.         append(&pbp,bp) ;               /* append data to header */
  274.         send_ax25(axp,pbp) ;    /* pass it off to ax25 code */
  275. }
  276.         
  277.  
  278. /* Perform a nodes broadcast on interface # ifno in the net/rom
  279.  * interface table.
  280.  */
  281.  
  282. void nr_bcnodes(unsigned ifno)
  283. {
  284.         struct mbuf *hbp, *dbp, *savehdr ;
  285.         struct nrroute_tab *rp ;
  286.         struct nrnbr_tab *np ;
  287.         struct nr_bind * bp ;
  288.         struct nr3dest nrdest ;
  289.         int i, didsend = 0, numdest = 0 ;
  290.         register char *cp ;
  291.         struct interface *axif = nrifaces[ifno].interface ;
  292.         
  293.         /* prepare the header */
  294.         if ((hbp = alloc_mbuf(NR3NODEHL)) == NULLBUF)
  295.                 return ;
  296.                 
  297.         hbp->cnt = NR3NODEHL ;  
  298.         
  299.         *hbp->data = NR3NODESIG ;
  300.         memcpy(hbp->data+1,nrifaces[ifno].alias,ALEN) ;
  301.  
  302.         /* Some people don't want to advertise any routes; they
  303.          * just want to be a terminal node.  In that case we just
  304.          * want to send our call and alias and be done with it.
  305.          */
  306.  
  307.         if (!nr_verbose) {
  308.                 (*axif->output)(axif, (char *)&nr_nodebc, axif->hwaddr,
  309.                                                 PID_NETROM,
  310.                                                 hbp) ;  /* send it */
  311.                 return ;
  312.         }
  313.         
  314.         /* make a copy of the header in case we need to send more than */
  315.         /* one packet */
  316.         savehdr = copy_p(hbp,NR3NODEHL) ;
  317.  
  318.         /* now scan through the routing table, finding the best routes */
  319.         /* and their neighbors.  create destination subpackets and append */
  320.         /* them to the header */
  321.         for (i = 0 ; i < NRNUMCHAINS ; i++) {
  322.                 for (rp = nrroute_tab[i] ; rp != NULLNRRTAB ; rp = rp->next) {
  323.                         /* look for best, non-obsolescent route */
  324.                         if ((bp = find_best(rp->routes,0)) == NULLNRBIND)
  325.                                 continue ;      /* no non-obsolescent routes found */
  326.                         if (bp->quality == 0)   /* this is a loopback route */
  327.                                 continue ;                      /* we never broadcast these */
  328.                         if (bp->quality < nr_autofloor) /* below threshhold route */
  329.                                 continue ;              /* so don't broadcast it */
  330.                         np = bp->via ;
  331.                         /* insert best neighbor */
  332.                         memcpy(nrdest.neighbor.call,np->call,ALEN) ;
  333.                         nrdest.neighbor.ssid = np->call[ALEN] ;
  334.                         /* insert destination from route table */
  335.                         nrdest.dest = rp->call ;
  336.                         /* insert alias from route table */
  337.                         strcpy(nrdest.alias,rp->alias) ;
  338.                         /* insert quality from binding */
  339.                         nrdest.quality = bp->quality ;
  340.                         /* create a network format destination subpacket */
  341.                         if ((dbp = htonnrdest(&nrdest)) == NULLBUF) {
  342.                                 free_p(hbp) ;   /* drop the whole idea ... */
  343.                                 free_p(savehdr) ;
  344.                                 return ;
  345.                         }
  346.                         append(&hbp,dbp) ;      /* append to header and others */
  347.                         /* see if we have appended as many destinations */
  348.                         /* as we can fit into a single broadcast.  If we */
  349.                         /* have, go ahead and send them out. */
  350.                         if (++numdest == NRDESTPERPACK) {       /* filled it up */
  351.                                 didsend = 1 ;   /* indicate that we did broadcast */
  352.                                 numdest = 0 ;   /* reset the destination counter */
  353.                                 (*axif->output)(axif, (char *)&nr_nodebc, axif->hwaddr,
  354.                                                                 PID_NETROM,
  355.                                                                 hbp) ;  /* send it */
  356.                                 hbp = copy_p(savehdr,NR3NODEHL) ;       /* new header */
  357.                         }
  358.                 }
  359.         }
  360.  
  361.         /* Now, here is something totally weird.  If our interfaces */
  362.         /* have different callsigns than this one, advertise a very */
  363.         /* high quality route to them.  Is this a good idea?  I don't */
  364.         /* know.  However, it allows us to simulate a bunch of net/roms */
  365.         /* hooked together with a diode matrix coupler. */
  366.         for (i = 0 ; i < nr_numiface ; i++) {
  367.                 if (i == ifno)
  368.                         continue ;              /* don't bother with ours */
  369.                 cp = nrifaces[i].interface->hwaddr ;
  370.                 if (!addreq((struct ax25_addr *)axif->hwaddr,(struct ax25_addr *)cp)) {
  371.                         /* both destination and neighbor address */
  372.                         memcpy(&nrdest.dest,cp,AXALEN) ;
  373.                         memcpy(&nrdest.neighbor,cp,AXALEN) ;
  374.                         /* alias of the interface */
  375.                         strcpy(nrdest.alias,nrifaces[i].alias) ;
  376.                         /* and the very highest quality */
  377.                         nrdest.quality = 255 ;
  378.                         /* create a network format destination subpacket */
  379.                         if ((dbp = htonnrdest(&nrdest)) == NULLBUF) {
  380.                                 free_p(hbp) ;   /* drop the whole idea ... */
  381.                                 free_p(savehdr) ;
  382.                                 return ;
  383.                         }
  384.                         append(&hbp,dbp) ;      /* append to header and others */
  385.                         if (++numdest == NRDESTPERPACK) {       /* filled it up */
  386.                                 didsend = 1 ;   /* indicate that we did broadcast */
  387.                                 numdest = 0 ;   /* reset the destination counter */
  388.                                 (*axif->output)(axif, (char *)&nr_nodebc, axif->hwaddr,
  389.                                                                 PID_NETROM,
  390.                                                                 hbp) ;  /* send it */
  391.                                 hbp = copy_p(savehdr,NR3NODEHL) ;       /* new header */
  392.                         }
  393.                 }
  394.         }
  395.                         
  396.         /* If we have a partly filled packet left over, or we never */
  397.         /* sent one at all, we broadcast: */
  398.         if (!didsend || numdest > 0)
  399.                 (*axif->output)(axif, (char *)&nr_nodebc, axif->hwaddr, PID_NETROM, hbp) ;
  400.  
  401.         free_p(savehdr) ;       /* free the header copy */
  402. }
  403.  
  404.  
  405. /* initialize fake arp entry for netrom */
  406. void nr3arp(void)
  407. {
  408.         arp_init(ARP_NETROM,AXALEN,0,0,NULLCHAR,psax25,setpath) ;
  409. }
  410.  
  411. /* attach the net/rom interface.  no parms for now. */
  412. int nr_attach(int argc, char **argv)
  413. {
  414.         argc = argc;
  415.         argv = argv;
  416.  
  417.         if (nr_interface != (struct interface *)0) {
  418.                 cwprintf(NULL, "netrom interface already attached\r\n") ;
  419.                 return -1 ;
  420.         }
  421.  
  422.         nr3arp() ;
  423.         
  424.         nr_interface = (struct interface *)calloc(1,sizeof(struct interface)) ;
  425.         nr_interface->name = "netrom" ;
  426.         nr_interface->mtu = NR4MAXINFO ;
  427.         nr_interface->send = (int (*)())nr_send ;
  428.         nr_interface->next = ifaces ;
  429.         ifaces = nr_interface ;
  430.         return 0 ;
  431. }
  432.  
  433. /* This function checks an ax.25 address and interface number against
  434.  * the filter table and mode, and returns 1 if the address is to be
  435.  * accepted, and 0 if it is to be filtered out.
  436.  */
  437. static int accept_bc(struct ax25_addr *addr, unsigned ifnum)
  438. {
  439.         struct nrnf_tab *fp ;
  440.  
  441.         if (nr_nfmode == NRNF_NOFILTER)         /* no filtering in effect */
  442.                 return 1 ;
  443.  
  444.         fp = find_nrnf(addr,ifnum) ;            /* look it up */
  445.         
  446.         if ((fp != NULLNRNFTAB && nr_nfmode == NRNF_ACCEPT)
  447.                 || (fp == NULLNRNFTAB && nr_nfmode == NRNF_REJECT))
  448.                 return 1 ;
  449.         else
  450.                 return 0 ;
  451. }
  452.  
  453.  
  454. /* receive and process node broadcasts. */
  455. void nr_nodercv(struct interface *interface, struct ax25_addr *source, struct mbuf *bp)
  456. {
  457.         register int ifnum ;
  458.         char bcalias[7] ;
  459.         struct nr3dest ds ;
  460.         char sbuf[AXALEN*3] ;
  461.         
  462.         /* First, see if this is even a net/rom interface: */
  463.         for (ifnum = 0 ; ifnum < nr_numiface ; ifnum++)
  464.                 if (interface == nrifaces[ifnum].interface)
  465.                         break ;
  466.                         
  467.         if (ifnum == nr_numiface) {     /* not in the interface table */
  468.                 free_p(bp) ;
  469.                 return ;
  470.         }
  471.  
  472.         if (!accept_bc(source,ifnum)) { /* check against filter */
  473.                 free_p(bp) ;
  474.                 return ;
  475.         }
  476.         
  477.         /* See if it has a routing broadcast signature: */
  478.         if (uchar(pullchar(&bp)) != NR3NODESIG) {
  479.                 free_p(bp) ;
  480.                 return ;
  481.         }
  482.  
  483.         /* now try to get the alias */
  484.         if (pullup(&bp,bcalias,ALEN) < ALEN) {
  485.                 free_p(bp) ;
  486.                 return ;
  487.         }
  488.  
  489.         bcalias[ALEN] = '\0' ;          /* null terminate */
  490.  
  491.         /* copy source address and convert to arp format */
  492.         memcpy(sbuf,source->call,ALEN) ;
  493.         sbuf[ALEN] = (source->ssid | E) ;       /* terminate */
  494.         
  495.         /* enter the neighbor into our routing table */
  496.         if (nr_routeadd(bcalias,source,ifnum,nrifaces[ifnum].quality,
  497.                                         sbuf, 0, 0) == -1) {
  498.                 free_p(bp) ;
  499.                 return ;
  500.         }
  501.         
  502.         /* we've digested the header; now digest the actual */
  503.         /* routing information */
  504.         while (ntohnrdest(&ds,&bp) != -1) {
  505.                 /* ignore routes to me! */
  506.                 if (ismycall(&ds.dest))
  507.                         continue ;
  508.                 /* ignore routes below the minimum quality threshhold */
  509.                 if (ds.quality < nr_autofloor)
  510.                         continue ;
  511.                 /* ignore loopback paths to ourselves */
  512.                 if (ismycall(&ds.neighbor))
  513.                         continue;
  514.                 else
  515.                         ds.quality = ((ds.quality * nrifaces[ifnum].quality + 128)
  516.                                                   / 256) & 0xff ;
  517.                 if (nr_routeadd(ds.alias,&ds.dest,ifnum,ds.quality,sbuf,0,0)
  518.                         == -1)
  519.                         break ;
  520.         }
  521.                         
  522.         free_p(bp) ;    /* This will free the mbuf if anything fails above */
  523. }
  524.  
  525.  
  526. /* The following are utilities for manipulating the routing table */
  527.  
  528. /* hash function for callsigns.  Look familiar? */
  529. int16 nrhash(struct ax25_addr *s)
  530. {
  531.         register char x ;
  532.         register int i ;
  533.         register char *cp ;
  534.  
  535.         x = 0 ;
  536.         cp = s->call ;
  537.         for (i = ALEN ; i !=0 ; i--)
  538.                 x ^= *cp++ & 0xfe ;
  539.         x ^= s->ssid & SSID ;
  540.         return uchar(x) % NRNUMCHAINS ;
  541. }
  542.  
  543. /* Find a neighbor table entry.  Neighbors are determined by
  544.  * their callsign and the interface number.  This takes care
  545.  * of the case where the same switch or hosts uses the same
  546.  * callsign on two different channels.  This isn't done by
  547.  * net/rom, but it might be done by stations running *our*
  548.  * software.
  549.  */
  550. struct nrnbr_tab *find_nrnbr(register struct ax25_addr *addr, unsigned ifnum)
  551. {
  552.         int16 hashval ;
  553.         register struct nrnbr_tab *np ;
  554.         struct ax25_addr ncall ;
  555.  
  556.         /* Find appropriate hash chain */
  557.         hashval = nrhash(addr) ;
  558.  
  559.         /* search hash chain */
  560.         for (np = nrnbr_tab[hashval] ; np != NULLNTAB ; np = np->next) {
  561.                 memcpy(ncall.call,np->call,ALEN) ;      /* convert first in */
  562.                 ncall.ssid = np->call[ALEN] ; /* list to ax25 address format */
  563.                 if (addreq(&ncall,addr) && np->interface == ifnum) {
  564.                         return np ;
  565.                 }
  566.         }
  567.         return NULLNTAB ;
  568. }
  569.  
  570.  
  571. /* Find a route table entry */
  572. struct nrroute_tab *find_nrroute(register struct ax25_addr *addr)
  573. {
  574.         int16 hashval ;
  575.         register struct nrroute_tab *rp ;
  576.  
  577.         /* Find appropriate hash chain */
  578.         hashval = nrhash(addr) ;
  579.  
  580.         /* search hash chain */
  581.         for (rp = nrroute_tab[hashval] ; rp != NULLNRRTAB ; rp = rp->next) {
  582.                 if (addreq(&rp->call,addr)) {
  583.                         return rp ;
  584.                 }
  585.         }
  586.         return NULLNRRTAB ;
  587. }
  588.  
  589. /* Try to find the AX.25 address of a node with the given alias.  Return */
  590. /* a pointer to the AX.25 address if found, otherwise NULLAXADDR.  The alias */
  591. /* should be a six character, blank-padded, upper-case string. */
  592.  
  593. struct ax25_addr *find_nralias(char *alias)
  594. {
  595.         int i ;
  596.         register struct nrroute_tab *rp ;
  597.  
  598.         /* Since the route entries are hashed by ax.25 address, we'll */
  599.         /* have to search all the chains */
  600.         
  601.         for (i = 0 ; i < NRNUMCHAINS ; i++)
  602.                 for (rp = nrroute_tab[i] ; rp != NULLNRRTAB ; rp = rp->next)
  603.                         if (strncmp(alias, rp->alias, 6) == 0)
  604.                                 return &rp->call ;
  605.  
  606.         /* If we get to here, we're out of luck */
  607.  
  608.         return NULLAXADDR ;
  609. }
  610.  
  611.         
  612. /* Find a binding in a list by its neighbor structure's address */
  613. struct nr_bind *find_binding(struct nr_bind *list,
  614.                              register struct nrnbr_tab *neighbor)
  615. {
  616.         register struct nr_bind *bp ;
  617.  
  618.         for(bp = list ; bp != NULLNRBIND ; bp = bp->next)
  619.                 if (bp->via == neighbor)
  620.                         return bp ;
  621.  
  622.         return NULLNRBIND ;
  623. }
  624.  
  625. /* Find the worst quality non-permanent binding in a list */
  626. static struct nr_bind *find_worst(struct nr_bind *list)
  627. {
  628.         register struct nr_bind *bp ;
  629.         struct nr_bind *worst = NULLNRBIND ;
  630.         unsigned minqual = 1000 ;       /* infinity */
  631.  
  632.         for (bp = list ; bp != NULLNRBIND ; bp = bp->next)
  633.                 if (!(bp->flags & NRB_PERMANENT) && bp->quality < minqual) {
  634.                         worst = bp ;
  635.                         minqual = bp->quality ;
  636.                 }
  637.  
  638.         return worst ;
  639. }
  640.  
  641. /* Find the best binding of any sort in a list.  If obso is 1,
  642.  * include entries below the obsolescence threshhold in the
  643.  * search (not used when this is called for routing broadcasts).
  644.  * If it is 0, routes below the threshhold are treated as
  645.  * though they don't exist.
  646.  */
  647. static struct nr_bind *find_best(struct nr_bind *list, unsigned obso)
  648. {
  649.         register struct nr_bind *bp ;
  650.         struct nr_bind *best = NULLNRBIND ;
  651.         int maxqual = -1 ;      /* negative infinity */
  652.  
  653.         for (bp = list ; bp != NULLNRBIND ; bp = bp->next)
  654.                 if ((int)bp->quality > maxqual)
  655.                         if (obso || bp->obsocnt >= obso_minbc) {
  656.                                 best = bp ;
  657.                                 maxqual = bp->quality ;
  658.                         }
  659.  
  660.         return best ;
  661. }
  662.  
  663. /* Add a route to the net/rom routing table */
  664. int nr_routeadd(char *alias, struct ax25_addr *dest, unsigned ifnum,
  665.                 unsigned quality, char *neighbor, unsigned permanent,
  666.                 unsigned record)
  667. {
  668.         struct nrroute_tab *rp ;
  669.         struct nr_bind *bp ;
  670.         struct nrnbr_tab *np ;
  671.         int16 rhash, nhash ;
  672.         struct ax25_addr ncall ;
  673.  
  674.         /* See if a routing table entry exists for this destination */
  675.         if ((rp = find_nrroute(dest)) == NULLNRRTAB) {
  676.                 if ((rp =
  677.                          (struct nrroute_tab *)calloc(1,sizeof(struct nrroute_tab)))
  678.                         == NULLNRRTAB)
  679.                         return -1 ;
  680.                 else {                  /* create a new route table entry */
  681.                         strncpy(rp->alias,alias,6) ;
  682.                         rp->call = *dest ;
  683.                         rhash = nrhash(dest) ;
  684.                         rp->next = nrroute_tab[rhash] ;
  685.                         if (rp->next != NULLNRRTAB)
  686.                                 rp->next->prev = rp ;
  687.                         nrroute_tab[rhash] = rp ;       /* link at head of hash chain */
  688.                 }
  689.         }
  690.         else
  691.                 {
  692.                 if (permanent || !strncmp(rp->alias,"##temp",6))
  693.                         strncpy(rp->alias,alias,6) ;    /* update the alias */
  694.                 }
  695.  
  696.         /* See if an entry exists for this neighbor */
  697.         memcpy(ncall.call,neighbor,ALEN) ;      /* no digis included */
  698.         ncall.ssid = neighbor[ALEN] ;
  699.         if ((np = find_nrnbr(&ncall,ifnum)) == NULLNTAB) {
  700.                 if ((np =
  701.                          (struct nrnbr_tab *)calloc(1,sizeof(struct nrnbr_tab)))
  702.                          == NULLNTAB) {
  703.                         if (rp->num_routes == 0) {      /* we just added to table */
  704.                                 nrroute_tab[rhash] = rp->next ;
  705.                                 free(rp) ;                              /* so get rid of it */
  706.                         }
  707.                         return -1 ;
  708.                 }
  709.                 else {          /* create a new neighbor entry */
  710.                         memcpy(np->call,neighbor,3 * AXALEN) ;
  711.                         np->interface = ifnum ;
  712.                         nhash = nrhash(&ncall) ;
  713.                         np->next = nrnbr_tab[nhash] ;
  714.                         if (np->next != NULLNTAB)
  715.                                 np->next->prev = np ;
  716.                         nrnbr_tab[nhash] = np ;
  717.                 }
  718.         }
  719.         else if (permanent) {           /* force this path to the neighbor */
  720.                 memcpy(np->call,neighbor,3 * AXALEN) ;
  721.         }
  722.                 
  723.         /* See if there is a binding between the dest and neighbor */
  724.         if ((bp = find_binding(rp->routes,np)) == NULLNRBIND) {
  725.                 if ((bp =
  726.                          (struct nr_bind *)calloc(1,sizeof(struct nr_bind)))
  727.                         == NULLNRBIND) {
  728.                         if (rp->num_routes == 0) {      /* we just added to table */
  729.                                 nrroute_tab[rhash] = rp->next ;
  730.                                 free(rp) ;                              /* so get rid of it */
  731.                         }
  732.                         if (np->refcnt == 0) {          /* we just added it */
  733.                                 nrnbr_tab[nhash] = np->next ;
  734.                                 free(np) ;
  735.                         }
  736.                         return -1 ;
  737.                 }
  738.                 else {          /* create a new binding and link it in */
  739.                         bp->via = np ;  /* goes via this neighbor */
  740.                         bp->next = rp->routes ; /* link into binding chain */
  741.                         if (bp->next != NULLNRBIND)
  742.                                 bp->next->prev = bp ;
  743.                         rp->routes = bp ;
  744.                         rp->num_routes++ ;      /* bump route count */
  745.                         np->refcnt++ ;          /* bump neighbor ref count */
  746.                         bp->quality = quality ;
  747.                         bp->obsocnt = obso_init ;       /* use initial value */
  748.                         if (permanent)
  749.                                 bp->flags |= NRB_PERMANENT ;
  750.                         else if (record)        /* notice permanent overrides record! */
  751.                                 bp->flags |= NRB_RECORDED ;
  752.                 }
  753.         } else {
  754.                 if (permanent) {        /* permanent request trumps all */
  755.                         bp->quality = quality ;
  756.                         bp->obsocnt = obso_init ;
  757.                         bp->flags |= NRB_PERMANENT ;
  758.                         bp->flags &= ~NRB_RECORDED ;    /* perm is not recorded */
  759.                 } else if (!(bp->flags & NRB_PERMANENT)) {      /* not permanent */
  760.                         if (record) {   /* came from nr_route */
  761.                                 if (bp->flags & NRB_RECORDED) { /* no mod non-rec bindings */
  762.                                         bp->quality = quality ;
  763.                                         bp->obsocnt = obso_init ; /* freshen recorded routes */
  764.                                 }
  765.                         } else {                /* came from a routing broadcast */
  766.                                 bp->quality = quality ;
  767.                                 bp->obsocnt = obso_init ;
  768.                                 bp->flags &= ~NRB_RECORDED ; /* no longer a recorded route */
  769.                         }
  770.                 }
  771.         }
  772.                 
  773.         /* Now, check to see if we have too many bindings, and drop */
  774.         /* the worst if we do */
  775.         if (rp->num_routes > nr_maxroutes) {
  776.                 /* since find_worst never returns permanent entries, the */
  777.                 /* limitation on number of routes is circumvented for    */
  778.                 /* permanent routes */
  779.                 if ((bp = find_worst(rp->routes)) != NULLNRBIND) {
  780.                         memcpy(ncall.call,bp->via->call,ALEN) ;
  781.                         ncall.ssid = bp->via->call[ALEN] ;
  782.                         nr_routedrop(dest,&ncall,bp->via->interface) ;
  783.                 }
  784.         }
  785.  
  786.         return 0 ;
  787. }
  788.  
  789.  
  790. /* Drop a route to dest via neighbor */
  791. int nr_routedrop(struct ax25_addr *dest, struct ax25_addr *neighbor,
  792.                  unsigned ifnum)
  793. {
  794.         register struct nrroute_tab *rp ;
  795.         register struct nrnbr_tab *np ;
  796.         register struct nr_bind *bp ;
  797.  
  798.         if ((rp = find_nrroute(dest)) == NULLNRRTAB)
  799.                 return -1 ;
  800.  
  801.         if ((np = find_nrnbr(neighbor,ifnum)) == NULLNTAB)
  802.                 return -1 ;
  803.  
  804.         if ((bp = find_binding(rp->routes,np)) == NULLNRBIND)
  805.                 return -1 ;
  806.  
  807.         /* drop the binding first */
  808.         if (bp->next != NULLNRBIND)
  809.                 bp->next->prev = bp->prev ;
  810.         if (bp->prev != NULLNRBIND)
  811.                 bp->prev->next = bp->next ;
  812.         else
  813.                 rp->routes = bp->next ;
  814.  
  815.         free(bp) ;
  816.         rp->num_routes-- ;              /* decrement the number of bindings */
  817.         np->refcnt-- ;                  /* and the number of neighbor references */
  818.         
  819.         /* now see if we should drop the route table entry */
  820.         if (rp->num_routes == 0) {
  821.                 if (rp->next != NULLNRRTAB)
  822.                         rp->next->prev = rp->prev ;
  823.                 if (rp->prev != NULLNRRTAB)
  824.                         rp->prev->next = rp->next ;
  825.                 else
  826.                         nrroute_tab[nrhash(dest)] = rp->next ;
  827.  
  828.                 free(rp) ;
  829.         }
  830.  
  831.         /* and check to see if this neighbor can be dropped */
  832.         if (np->refcnt == 0) {
  833.                 if (np->next != NULLNTAB)
  834.                         np->next->prev = np->prev ;
  835.                 if (np->prev != NULLNTAB)
  836.                         np->prev->next = np->next ;
  837.                 else
  838.                         nrnbr_tab[nrhash(neighbor)] = np->next ;
  839.  
  840.                 free(np) ;
  841.         }
  842.         
  843.         return 0 ;
  844. }
  845.  
  846. /* Find the best neighbor for destination dest, in arp format */
  847. char *nr_getroute(struct ax25_addr *dest)
  848. {
  849.         register struct nrroute_tab *rp ;
  850.         register struct nr_bind *bp ;
  851.  
  852.         if ((rp = find_nrroute(dest)) == NULLNRRTAB)
  853.                 return NULLCHAR ;
  854.  
  855.         if ((bp = find_best(rp->routes,1)) == NULLNRBIND)       /* shouldn't happen! */
  856.                 return NULLCHAR ;
  857.  
  858.         return bp->via->call ;
  859. }
  860.  
  861. /* Find an entry in the filter table */
  862. struct nrnf_tab *find_nrnf(register struct ax25_addr *addr, unsigned ifnum)
  863. {
  864.         int16 hashval ;
  865.         register struct nrnf_tab *fp ;
  866.  
  867.         /* Find appropriate hash chain */
  868.         hashval = nrhash(addr) ;
  869.  
  870.         /* search hash chain */
  871.         for (fp = nrnf_tab[hashval] ; fp != NULLNRNFTAB ; fp = fp->next) {
  872.                 if (addreq(&fp->neighbor,addr) && fp->interface == ifnum) {
  873.                         return fp ;
  874.                 }
  875.         }
  876.  
  877.         return NULLNRNFTAB ;
  878. }
  879.  
  880. /* Add an entry to the filter table.  Return 0 on success,
  881.  * -1 on failure
  882.  */
  883. int nr_nfadd(struct ax25_addr *addr, unsigned ifnum)
  884. {
  885.         struct nrnf_tab *fp ;
  886.         int16 hashval ;
  887.         
  888.         if (find_nrnf(addr,ifnum) != NULLNRNFTAB)
  889.                 return 0 ;      /* already there; it's a no-op */
  890.  
  891.         if ((fp = (struct nrnf_tab *)calloc(1,sizeof(struct nrnf_tab)))
  892.                 == NULLNRNFTAB)
  893.                 return -1 ;     /* no storage */
  894.  
  895.         hashval = nrhash(addr) ;
  896.         fp->neighbor = *addr ;
  897.         fp->interface = ifnum ;
  898.         fp->next = nrnf_tab[hashval] ;
  899.         if (fp->next != NULLNRNFTAB)
  900.                 fp->next->prev = fp ;
  901.         nrnf_tab[hashval] = fp ;
  902.  
  903.         return 0 ;
  904. }
  905.  
  906. /* Drop a neighbor from the filter table.  Returns 0 on success, -1
  907.  * on failure.
  908.  */
  909. int nr_nfdrop(struct ax25_addr *addr, unsigned ifnum)
  910. {
  911.         struct nrnf_tab *fp ;
  912.  
  913.         if ((fp = find_nrnf(addr,ifnum)) == NULLNRNFTAB)
  914.                 return -1 ;     /* not in the table */
  915.  
  916.         if (fp->next != NULLNRNFTAB)
  917.                 fp->next->prev = fp->prev ;
  918.         if (fp->prev != NULLNRNFTAB)
  919.                 fp->prev->next = fp->next ;
  920.         else
  921.                 nrnf_tab[nrhash(addr)] = fp->next ;
  922.  
  923.         free(fp) ;
  924.  
  925.         return 0 ;
  926. }
  927.